package com.guaika.reggie.utils;

import com.alibaba.fastjson.JSON;
import com.guaika.reggie.entity.TreeMenu;
import org.reflections.Reflections;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author TangCheng
 * @date 2022/9/21 18:49
 * @description 获取所有 controller和方法 构造树形结构
 */
@Component
public class TreeMenuUtils {

    /**
     * 获取所有的 权限信息， 并以树形结构进行返回
     */
    private static List<TreeMenu> treeMenuList = new ArrayList<>();

    @PostConstruct
    public void init() {

        Reflections reflections = new Reflections("com.guaika.reggie");
        // 获取 com.itheima.reggie 包路径下 所有使用@RestController 注解的类
        Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(RestController.class);
        // 对这些类循环进行处理
        typesAnnotatedWith.forEach(cls -> {

            // 获取完整的类名称，比如: com.itheima.reggie.controller.AdressController
            String name = cls.getName();
            // 对名称进行裁剪，只要有用部分，比如：AddressController
            name = name.substring(name.lastIndexOf(".") + 1);

            // 因为类上面 会放置公共路径，比如 @RequestMapping("/address")，所以需要解析 并获取到RequestMapping 注解
            RequestMapping clsRequestMapping = cls.getAnnotation(RequestMapping.class);
            // basePath 用来记录请求的公共部分
            String basePath = "";

            if (clsRequestMapping != null) {
                // 获取 requestMapping的 资源路径，即value
                String[] clsValues = clsRequestMapping.value();
                // 如果value有值，那么这部分就是 公共的资源路径
                if (clsValues != null && clsValues.length > 0) {
                    basePath = clsValues[0];
                }
            }

            // 初始化层级结构，clsSubTreeList 用来存储该controller下面的方法信息
            List<TreeMenu> clsSubTreeList = new ArrayList<>();
            // controller类的根节点，后续子节点由这里进行发散
            TreeMenu treeMenu = TreeMenu.builder()
                    .id("PID::" + name)
                    .label(name)
                    .children(clsSubTreeList)
                    .build();

            // 树形结构的最外层，只记录类的信息
            treeMenuList.add(treeMenu);

            // 获取这个类的所有方法
            Method[] declaredMethods = cls.getDeclaredMethods();

            // 循环处理方法
            for (Method method : declaredMethods) {

                String methodType = null;
                String childPath = null;

                // 判断方法是否有 RequestMapping 注解，有的话，解析获取 value和method
                if (method.isAnnotationPresent(RequestMapping.class)) {

                    RequestMapping nowAnnotation = method.getAnnotation(RequestMapping.class);
                    RequestMethod[] requestMethods = nowAnnotation.method();
                    String[] methodValues = nowAnnotation.value();

                    if (methodValues != null && methodValues.length > 0) {
                        childPath = methodValues[0];
                    }

                    if (requestMethods != null && requestMethods.length > 0) {
                        methodType = requestMethods[0].name().toUpperCase();
                    }

                    // 判断方法是否有 GetMapping 注解，有的话，解析获取 value和method，后续不再解释
                } else if (method.isAnnotationPresent(GetMapping.class)) {

                    methodType = "GET";
                    GetMapping nowAnnotation = method.getAnnotation(GetMapping.class);
                    String[] methodValues = nowAnnotation.value();

                    if (methodValues != null && methodValues.length > 0) {
                        childPath = methodValues[0];
                    }

                } else if (method.isAnnotationPresent(PostMapping.class)) {

                    methodType = "POST";
                    PostMapping nowAnnotation = method.getAnnotation(PostMapping.class);
                    String[] methodValues = nowAnnotation.value();

                    if (methodValues != null && methodValues.length > 0) {
                        childPath = methodValues[0];
                    }

                } else if (method.isAnnotationPresent(PutMapping.class)) {

                    methodType = "PUT";
                    PutMapping nowAnnotation = method.getAnnotation(PutMapping.class);
                    String[] methodValues = nowAnnotation.value();

                    if (methodValues != null && methodValues.length > 0) {
                        childPath = methodValues[0];
                    }

                } else if (method.isAnnotationPresent(DeleteMapping.class)) {

                    methodType = "DELETE";
                    DeleteMapping nowAnnotation = method.getAnnotation(DeleteMapping.class);
                    String[] methodValues = nowAnnotation.value();

                    if (methodValues != null && methodValues.length > 0) {
                        childPath = methodValues[0];
                    }

                }

                // 构建这个方法的 TreeMenu
                if (childPath == null && methodType == null) {
                    continue;
                } else {
                    if (childPath == null) {
                        childPath = "";
                    } else if (!childPath.startsWith("/")) {
                        childPath = "/" + childPath;
                    }
                }
                TreeMenu subTreeMenu = TreeMenu.builder()
                        .id(methodType + " " + basePath + childPath)
                        .label(methodType + " " + basePath + childPath)
                        .build();

                clsSubTreeList.add(subTreeMenu);
            }
        });

        // 按照 id 进行培训
        treeMenuList = treeMenuList.stream().sorted(Comparator.comparing(TreeMenu::getId)).collect(Collectors.toList());

    }

    /**
     * 获取所有的 树形菜单
     *
     * @return
     */
    public static List<TreeMenu> getAllMenus() {
        return treeMenuList;
    }
}
